<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>发布订阅测试</title>
  </head>
  <body>
    <button id="btn">发布信息</button>
  </body>
</html>
<script>
  class EvenetBus {
    constructor() {
      this.events = new Map();
    }
    on(eventName, callback) {
      if (!this.events.has(eventName)) {
        this.events.set(eventName, new Set());
      }
      const eventNameSet = this.events.get(eventName);
      eventNameSet.add(callback);
      return this;
    }

    emit(eventName, ...args) {
      if (!this.events.has(eventName)) {
        return;
      }
      const eventNameSet = this.events.get(eventName);
      eventNameSet.forEach((cb) => {
        try {
          cb(...args);
        } catch (err) {
          console.log(err);
        }
      });
      return this;
    }

    off(eventName, callback) {
      if (callback) {
        const eventCallbacks = this.events.get(eventName);
        eventCallbacks.delete(callback);
      } else {
        this.events.delete(eventName);
      }
      return this;
    }

    once(eventName, callback) {   
      const onceFn = (...args) => {
        callback(...args);
        this.off(eventName, onceFn);
      };
      this.on(eventName, onceFn);
      return this;
    }
  }

  const $bus = new EvenetBus();
  function testFn(val) {
    console.log("val", val);
  }
  $bus.once("test", testFn);
  btn.onclick = function () {
    $bus.emit("test", {
      name: "monica",
      age: 9,
    });
  };
//   setTimeout(() => {
//     $bus.off("test", testFn);
//   }, 2000);
</script>
